/**
 * Principal.java
 * @author Paulo Chang, Carnet 11076
 * @author Oscar Castañeda, Carnet 11086
 * @author Francisco Martínez, Carnet 11096
 * @since 27/10/2011
 * Modificado por última vez el 13/11/2011.
 * Descripción: Clase pricipal en la cual se ejecuta el programa.
 */


import java.awt.event.WindowEvent;
import javax.swing.*;
import java.io.*;


public class Principal {
    
    private static ConexionBD baseDatos;
    private static JTabbedPane principal;
    private static JFrame frame;
    private static ControlCategoria categoriasHechas;
    private static BusquedaPanel busquedaPanel;
    private static Opciones opciones;
    private static AjustesPanel ajustes;
    private static CategoriasPanel categorias;
    private static StringEncrypter encriptador;
    private static String usuario, contrasenaEncriptada;
    
    /**
     * Permite seleccionar el usuario a utilizar en la base de datos MySQL.
     * @param usuario String con el nombre del usuario.
     * @throws NoExisteUsuario Excepción lanzada si el usuario buscado no existe.
     */
    public void usarUsuario(String usuario) throws NoExisteUsuario{
        boolean sePudo=baseDatos.usarBD(usuario);
        if(!sePudo){
            throw new NoExisteUsuario();
        }          
    }
    
    /**
     * Permite a un usuario ya existente iniciar sesión.
     * @param usuario2 String con el nombre del usuario de interés.
     * @param contrasena String con la contraseña ingresada por el usuario para iniciar su sesión.
     * @throws ContrasenaInvalida Exception lanzada si la contraseña ingresada no coincide con la real.
     */
    public void logIn(String usuario2, String contrasena) throws ContrasenaInvalida{
        String realContrasena;
        usuario=usuario2;
        try {
                FileInputStream fIS = new FileInputStream(usuario+".dat");
                ObjectInputStream os = new ObjectInputStream(fIS);
                realContrasena=(String) os.readObject();
                categoriasHechas=(ControlCategoria)os.readObject();
                os.close();                   
            }catch (Exception ex){
               throw new ContrasenaInvalida("No se ha podido encontrar su usuario");
            }
        encriptador=new StringEncrypter(contrasena);
        contrasenaEncriptada=realContrasena;
        realContrasena=encriptador.decrypt(realContrasena);
        if(!contrasena.equals(realContrasena) || contrasena==null){
            encriptador=null;
            throw new ContrasenaInvalida("Contraseña incorrecta");
        }
        categorias = new CategoriasPanel(baseDatos, usuario, categoriasHechas, false, encriptador);
    }
    
    /**
     * Permite a un nuevo usuario iniciar su sesión.
     * @param usuario2 String con el nombre del nuevo usuario.
     * @param contrasena String con la contraseña del nuevo usuario.
     */
    public void signIn(String usuario2, String contrasena){
        usuario=usuario2;
        categoriasHechas = new ControlCategoria();
        baseDatos.crearBD(usuario);
        encriptador=new StringEncrypter(contrasena);
        contrasenaEncriptada=encriptador.encrypt(contrasena);
        categorias = new CategoriasPanel(baseDatos, usuario, categoriasHechas, true, encriptador); 
    }
    
    /**
     * Permite abrir la ventana en la cual se ejecuta el programa principal.
     * Es decir, la ventana desde la cual se puede consultar las tablas de cada categoría
     * así como modificar las categorías existentes.
     */
    public static void programa(){
        try{
            //Crear el frame
            frame = new JFrame ("Billetera Virtual    POF-cket");
            //Al cerrarse, se guardará la contraseña y las categorías hechas en un archivo .dat.
            frame.addWindowListener(new java.awt.event.WindowAdapter() {
                public void windowClosing(WindowEvent winEvt) {
                    try {
                        FileOutputStream fs = new FileOutputStream(usuario+".dat");
                        ObjectOutputStream os = new ObjectOutputStream(fs);
                        os.writeObject(contrasenaEncriptada);
                        os.writeObject(categoriasHechas);
                        os.close();
                    }catch (Exception ex) {
                        JOptionPane.showMessageDialog(null, "Lo sentimos: Hubo un error al intentar guardar sus archivos", "Error", JOptionPane.ERROR_MESSAGE);
                    }
                    baseDatos.desconectar();
                    System.exit(0); 
                }
            });
            principal = new JTabbedPane();
            
            //Cargar las Categorías
            
            opciones = categorias.getOpciones();
            busquedaPanel = new BusquedaPanel(opciones);
            ajustes = new AjustesPanel(baseDatos, categoriasHechas, categorias, opciones, contrasenaEncriptada, encriptador);
            
            principal.add("Categorías", categorias);
            principal.add("Búsqueda", busquedaPanel);
            principal.add("Ajustes", ajustes);
            frame.getContentPane().add(principal);
            frame.pack();
            frame.setVisible(true);
                  
        }catch(Exception e){
            JOptionPane.showMessageDialog(null, "<html>Error inesperado en la ejecución del programa.<br>Contacte a su proveedor.</html>", "Error", JOptionPane.ERROR_MESSAGE);
        }
    }
    
    /**
     * Permite cambiar la contraseña maestra del programa.
     * @param nuevaContrasenaEncriptada String con la nueva contraseña encriptada.
     * @param nuevoEncriptador StringEncrypter nuevo construido a partir de la nueva contraseña encriptada.
     */
    public static void cambiarContrasena(String nuevaContrasenaEncriptada,StringEncrypter nuevoEncriptador){
        contrasenaEncriptada=nuevaContrasenaEncriptada;
        String contrasena=nuevoEncriptador.decrypt(nuevaContrasenaEncriptada);
        try {
            FileOutputStream fs = new FileOutputStream(usuario+".dat");
            ObjectOutputStream os = new ObjectOutputStream(fs);
            os.writeObject(contrasenaEncriptada);
            os.writeObject(categoriasHechas);
            os.close();
        }catch (Exception ex) {
            JOptionPane.showMessageDialog(null, "Lo sentimos: Hubo un error al intentar guardar sus archivos", "Error", JOptionPane.ERROR_MESSAGE);
        }
        frame.dispose();
        try {
            FileInputStream fIS = new FileInputStream(usuario+".dat");
            ObjectInputStream os = new ObjectInputStream(fIS);
            String realContrasena=(String) os.readObject();
            categoriasHechas=(ControlCategoria)os.readObject();
            os.close();                   
        }catch (Exception ex){
            System.exit(0);
        }
        encriptador=nuevoEncriptador;
        categorias = new CategoriasPanel(baseDatos, usuario, categoriasHechas, false, encriptador);

        programa();
    }
    
    /**
     * Método principal. Se establece el look & feel, se crea una nueva conexión a la base
     * de datos y se colocan y muestran los compenentes a utilizar.
     * @param args Parámetro opcional propio del método main. 
     */
    public static void main (String args[]){
        try {
            UIManager.setLookAndFeel(ch.randelshofer.quaqua.QuaquaManager.getLookAndFeel());
        } catch (Exception e){
            //No se pudo cargar el look & feel deseado.
        }
        baseDatos = new ConexionBD();
        if (baseDatos.conectar()){
            Principal principal=new Principal();
            IngresarFrame framecito=new IngresarFrame(principal);
            framecito.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            framecito.pack();
            framecito.setVisible(true);       
        }else
            //Si no se logra establecer la conexión a la base de datos.
            JOptionPane.showMessageDialog(new JFrame(), "La aplicación se cerrará.");
    }
}